package net.borlis.sample.web.context;

import javax.enterprise.context.spi.CreationalContext;
import javax.enterprise.inject.spi.Bean;
import javax.enterprise.inject.spi.BeanManager;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import java.lang.reflect.Type;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * Utility class used by Web Service implementation to load CDI beans in an non EE environment like "Apache-Tomcat".
 * Needs at least Tomcat 6.
 *
 * @author Sascha Skorupa
 * @version 1.0
 * @created 12.11.2012
 */
public final class WeldBeanManager {

    private static final Logger LOGGER = Logger.getLogger(WeldBeanManager.class.getName());

    private static final String CDI_BEAN_MANAGER = "java:/comp/env/BeanManager";

    private WeldBeanManager() {
        // utility class
    }

    @SuppressWarnings("unchecked")
    public static <T> T loadBeanInstanceFor(Class<T> clazz) {
        try {
            BeanManager beanManager = loadBeanManager();
            Set<Bean<?>> beans = beanManager.getBeans(clazz);
            for (Bean<?> bean : beans) {
                Set<Type> beanTypes = bean.getTypes();
                for (Type type : beanTypes) {
                    if (type.equals(clazz)) {
                        Bean<T> tmp = (Bean<T>) bean;
                        CreationalContext<T> cc = beanManager.createCreationalContext(tmp);
                        return (T) beanManager.getReference(tmp, clazz, cc);
                    }
                }
            }
            throw new IllegalStateException("Cannot create bean for " + clazz.getSimpleName() + "!");
        } catch (Exception e) {
            String message = "Cannot create bean for " + clazz.getSimpleName() + "!";
            LOGGER.log(Level.SEVERE, message, e);
            throw new ExceptionInInitializerError(e);
        }
    }

    private static BeanManager loadBeanManager() throws InstantiationException {
        try {
            InitialContext ic = new InitialContext();
            return (BeanManager) ic.lookup(CDI_BEAN_MANAGER);
        } catch (NamingException e) {
            String message = "Cannot load BeanManager from JNDI.";
            LOGGER.log(Level.SEVERE, message, e);
            throw new IllegalStateException(message, e);
        }
    }
}